using System;

namespace PDUConverter
{
    /// <summary>
    /// Indicates how the user data is encoded, this class represents the TP-DCS field.
    /// </summary>
    /// <remarks>
    /// The TP-Data-Coding-Scheme field, defined in GSM 03.40, indicates the data coding scheme of the TP-UD field,
    /// and may indicate a message class. Any reserved codings shall be assumed to be the GSM default alphabet
    /// (the same as codepoint 00000000) by a receiving entity. The octet is used according to a coding group
    /// which is indicated in bits 7..4
    /// </remarks>
    public abstract class DataCodingScheme
    {
        /// <summary>Offset for bit 0 value.</summary>
        protected const byte bit0offset = 1;
        /// <summary>Offset for bit 1 value.</summary>
        protected const byte bit1offset = 2;
        /// <summary>Offset for bit 2 value.</summary>
        protected const byte bit2offset = 4;
        /// <summary>Offset for bit 3 value.</summary>
        protected const byte bit3offset = 8;
        /// <summary>Offset for bit 4 value.</summary>
        protected const byte bit4offset = 0x10;
        /// <summary>Offset for bit 5 value.</summary>
        protected const byte bit5offset = 0x20;
        /// <summary>Offset for bit 6 value.</summary>
        protected const byte bit6offset = 0x40;
        /// <summary>Offset for bit 7 value.</summary>
        protected const byte bit7offset = 0x80;
        /// <summary>
        /// Specifies message class 0 (immediate display) and UCS2 (16-bit) alphabet.
        /// </summary>
        public const byte Class0_16Bit = 0x18;
        /// <summary>
        /// Specifies message class 0 (immediate display) and 7-bit default alphabet.
        /// </summary>
        public const byte Class0_7Bit = 0x10;
        /// <summary>
        /// Specifies message class 0 (immediate display) and 8-bit data.
        /// </summary>
        public const byte Class0_8Bit = 20;
        /// <summary>
        /// Specifies message class 1 (ME specific) and UCS2 (16-bit) alphabet.
        /// </summary>
        public const byte Class1_16Bit = 0x19;
        /// <summary>
        /// Specifies message class 1 (ME specific) and 7-bit default alphabet.
        /// </summary>
        public const byte Class1_7Bit = 0x11;
        /// <summary>
        /// Specifies message class 1 (ME specific) and 8-bit data.
        /// </summary>
        public const byte Class1_8Bit = 0x15;
        /// <summary>
        /// Specifies message class 2 (SIM specific) and UCS2 (16-bit) alphabet.
        /// </summary>
        public const byte Class2_16Bit = 0x1a;
        /// <summary>
        /// Specifies message class 2 (SIM specific) and 7-bit default alphabet.
        /// </summary>
        public const byte Class2_7Bit = 0x12;
        /// <summary>
        /// Specifies message class 2 (SIM specific) and 8-bit data.
        /// </summary>
        public const byte Class2_8Bit = 0x16;
        /// <summary>
        /// Specifies message class 3 (TE specific) and UCS2 (16-bit) alphabet.
        /// </summary>
        public const byte Class3_16Bit = 0x1b;
        /// <summary>
        /// Specifies message class 3 (TE specific) and 7-bit default alphabet.
        /// </summary>
        public const byte Class3_7Bit = 0x13;
        /// <summary>
        /// Specifies message class 3 (TE specific) and 8-bit data.
        /// </summary>
        public const byte Class3_8Bit = 0x17;
        private const byte classValid = 0x10;
        private byte codingGroup;
        /// <summary>
        /// Specifies no message class and UCS2 (16-bit) alphabet.
        /// </summary>
        public const byte NoClass_16Bit = 8;
        /// <summary>
        /// Specifies no message class and 7-bit default alphabet.
        /// </summary>
        public const byte NoClass_7Bit = 0;
        /// <summary>
        /// Specifies no message class and 8-bit data.
        /// </summary>
        public const byte NoClass_8Bit = 4;

        /// <summary>
        /// Initializes a new instance of the <see cref="T:GsmComm.PduConverter.DataCodingScheme" /> class.
        /// </summary>
        /// <param name="dcs">The DCS byte to decode.</param>
        protected DataCodingScheme(byte dcs)
        {
            this.codingGroup = (byte) ((dcs >> 4) & 15);
        }

        /// <summary>
        /// Decodes the given DCS byte.
        /// </summary>
        /// <param name="dcs">The DCS octet to decode.</param>
        /// <returns>An object of type <see cref="T:GsmComm.PduConverter.DataCodingScheme" /> or one of its derived classes.</returns>
        public static DataCodingScheme Decode(byte dcs)
        {
            byte num = (byte) ((dcs >> 4) & 15);
            if (((dcs & 0x40) == 0) && ((dcs & 0x80) == 0))
            {
                return new GeneralDataCoding(dcs);
            }
            switch (num)
            {
                case 12:
                    return new MessageWaitingDiscard(dcs);

                case 13:
                    return new MessageWaitingStore(dcs);

                case 14:
                    return new MessageWaitingStoreUcs2(dcs);

                case 15:
                    return new MessageCoding(dcs);
            }
            return new ReservedCodingGroup(dcs);
        }

        /// <summary>
        /// Gets the coding group, that tells about the further contents of the data coding scheme.
        /// </summary>
        public byte CodingGroup
        {
            get
            {
                return this.codingGroup;
            }
        }

        /// <summary>
        /// Lists the available alphabets within a general data coding indication DCS.
        /// </summary>
        public enum Alphabets
        {
            DefaultAlphabet,
            EightBit,
            Ucs2,
            Reserved
        }

        /// <summary>
        /// Data coding/message class. Members can be combined.
        /// </summary>
        /// <remarks>At least a "Group" member must be specified.</remarks>
        [Flags]
        public enum DataCoding
        {
            /// <summary>
            /// 7-bit default alphabet
            /// </summary>
            Alpha7BitDefault = 0,
            /// <summary>
            /// 8-bit data
            /// </summary>
            Alpha8Bit = 4,
            /// <summary>
            /// Immediate display (alert)
            /// </summary>
            Class0 = 0,
            /// <summary>
            /// ME specific
            /// </summary>
            Class1 = 1,
            /// <summary>
            /// SIM specific
            /// </summary>
            Class2 = 2,
            /// <summary>
            /// TE specific
            /// </summary>
            Class3 = 3,
            /// <summary>
            /// Indicates the Data coding/message class group is being used.
            /// </summary>
            Group_DataCoding = 240
        }

        /// <summary>
        /// General data coding indication. Members can be combined.
        /// </summary>
        [Flags]
        public enum GeneralCoding : byte
        {
            /// <summary>
            /// Unicode (UCS2)
            /// </summary>
            Alpha16Bit = 8,
            /// <summary>
            /// 7-bit default alphabet (default)
            /// </summary>
            Alpha7BitDefault = 0,
            /// <summary>
            /// 8-bit data
            /// </summary>
            Alpha8Bit = 4,
            /// <summary>
            /// Reserved for future use
            /// </summary>
            AlphaReserved = 12,
            /// <summary>
            /// Immediate display (alert)
            /// </summary>
            Class0 = 0x10,
            /// <summary>
            /// ME specific
            /// </summary>
            Class1 = 0x11,
            /// <summary>
            /// SIM specific
            /// </summary>
            Class2 = 0x12,
            /// <summary>
            /// TE specific
            /// </summary>
            Class3 = 0x13,
            /// <summary>
            /// Data is compressed
            /// </summary>
            Compressed = 0x20,
            /// <summary>
            /// No class meaning (default)
            /// </summary>
            NoClass = 0,
            /// <summary>
            /// Data is uncompressed (default)
            /// </summary>
            Uncompressed = 0
        }

        /// <summary>
        /// Lists the available message codings within a data coding/message class DCS.
        /// </summary>
        public enum MessageCodings
        {
            DefaultAlphabet,
            EightBit
        }

        /// <summary>
        /// Message waiting indication. Members can be combined.
        /// </summary>
        /// <remarks>At least a "Group" member must be specified.</remarks>
        [Flags]
        public enum MessageWaiting : byte
        {
            /// <summary>
            /// Indicates a waiting E-Mail message.
            /// </summary>
            EMailMsgWaiting = 2,
            /// <summary>
            /// Indicates a waiting Fax message.
            /// </summary>
            FaxMsgWaiting = 1,
            /// <summary>
            /// The receiver may discard the contents of the message, and only
            /// present the indication to the user. Text included in the user
            /// data is in the default alphabet.
            /// </summary>
            Group_Discard_7BitDefault = 0xc0,
            /// <summary>
            /// The receiver shall store the contents of the message in addition
            /// to set the indication. Text included in the user
            /// data is in the uncompressed UCS2 alphabet.
            /// </summary>
            Group_Store_16Bit = 0xe0,
            /// <summary>
            /// The receiver shall store the contents of the message in addition
            /// to set the indication. Text included in the user
            /// data is in the default alphabet.
            /// </summary>
            Group_Store_7BitDefault = 0xd0,
            /// <summary>
            /// Indicates an other type of waiting message.
            /// </summary>
            OtherMsgWaiting = 3,
            /// <summary>
            /// Sets the indication active.
            /// </summary>
            SetIndicationActive = 8,
            /// <summary>
            /// Sets the indication inactive (default).
            /// </summary>
            SetIndicationInactive = 0,
            /// <summary>
            /// Indicates a waiting Voicemail message (default).
            /// </summary>
            VoicemailMsgWaiting = 0
        }
    }
}